<?php

/**
 * This file is part of the Propel package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license    MIT License
 */

require_once dirname(__FILE__) . '/PeerBuilder.php';

/**
 * Generates a PHP5 tree nested set Peer class for user object model (OM).
 *
 * This class produces the base tree nested set object class (e.g. BaseMyTable) which contains all
 * the custom-built accessor and setter methods.
 *
 * @author     heltem <heltem@o2php.com>
 * @package    propel.generator.builder.om
 */
class PHP5NestedSetPeerBuilder extends PeerBuilder
{

    /**
     * Gets the package for the [base] object classes.
     *
     * @return string
     */
    public function getPackage()
    {
        return parent::getPackage() . ".om";
    }

    /**
     * Returns the name of the current class being built.
     *
     * @return string
     */
    public function getUnprefixedClassname()
    {
        return $this->getBuildProperty('basePrefix') . $this->getStubObjectBuilder()->getUnprefixedClassname() . 'NestedSetPeer';
    }

    /**
     * Adds the include() statements for files that this class depends on or utilizes.
     *
     * @param string &$script The script will be modified in this method.
     */
    protected function addIncludes(&$script)
    {
        $script .= "
require '" . $this->getPeerBuilder()->getClassFilePath() . "';
";
    } // addIncludes()

    /**
     * Adds class phpdoc comment and opening of class.
     *
     * @param string &$script The script will be modified in this method.
     */
    protected function addClassOpen(&$script)
    {

        $table = $this->getTable();
        $tableName = $table->getName();
        $tableDesc = $table->getDescription();

        $script .= "
/**
 * Base static class for performing query operations on the tree contained by the '$tableName' table.
 *
 * $tableDesc
 *";
        if ($this->getBuildProperty('addTimeStamp')) {
            $now = strftime('%c');
            $script .= "
 * This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
 *
 * $now
 *";
        }
        $script .= "
 * @deprecated  Since Propel 1.5. Use the nested_set behavior instead of the NestedSet treeMode
 * @package    propel.generator." . $this->getPackage() . "
 */
abstract class " . $this->getClassname() . " extends " . $this->getPeerBuilder()->getClassName() . " implements NodePeer {
";
    }

    /**
     * Specifies the methods that are added as part of the basic OM class.
     * This can be overridden by subclasses that wish to add more methods.
     *
     * @see        ObjectBuilder::addClassBody()
     */
    protected function addClassBody(&$script)
    {
        $table = $this->getTable();

        // FIXME
        // - Probably the build needs to be customized for supporting
        // tables that are "aliases".  -- definitely a fringe usecase, though.

        $this->addConstants($script);

        $this->addCreateRoot($script);

        $this->addRetrieveRoot($script);

        $this->addInsertAsFirstChildOf($script);
        $this->addInsertAsLastChildOf($script);
        $this->addInsertAsPrevSiblingOf($script);
        $this->addInsertAsNextSiblingOf($script);
        $this->addInsertAsParentOf($script);

        $this->addInsertRoot($script);
        $this->addInsertParent($script);

        $this->addDeleteRoot($script);
        $this->addDeleteNode($script);

        $this->addMoveToFirstChildOf($script);
        $this->addMoveToLastChildOf($script);
        $this->addMoveToPrevSiblingOf($script);
        $this->addMoveToNextSiblingOf($script);

        $this->addRetrieveFirstChild($script);
        $this->addRetrieveLastChild($script);
        $this->addRetrievePrevSibling($script);
        $this->addRetrieveNextSibling($script);

        $this->addRetrieveTree($script);
        $this->addRetrieveBranch($script);
        $this->addRetrieveChildren($script);
        $this->addRetrieveDescendants($script);
        $this->addRetrieveSiblings($script);
        $this->addRetrieveParent($script);

        $this->addGetLevel($script);
        $this->addGetNumberOfChildren($script);
        $this->addGetNumberOfDescendants($script);
        $this->addGetPath($script);

        $this->addIsValid($script);
        $this->addIsRoot($script);
        $this->addIsLeaf($script);
        $this->addIsChildOf($script);
        $this->addIsChildOfOrSiblingTo($script);
        $this->addIsEqualTo($script);

        $this->addHasParent($script);
        $this->addHasPrevSibling($script);
        $this->addHasNextSibling($script);
        $this->addHasChildren($script);

        $this->addDeleteDescendants($script);

        $this->addGetNode($script);

        $this->addHydrateDescendants($script);
        $this->addHydrateChildren($script);

        $this->addShiftRParent($script);
        $this->addUpdateLoadedNode($script);
        $this->addUpdateDBNode($script);

        $this->addShiftRLValues($script);
        $this->addShiftRLRange($script);
    }

    /**
     * Closes class.
     *
     * @param string &$script The script will be modified in this method.
     */
    protected function addClassClose(&$script)
    {
        $script .= "
} // " . $this->getClassname() . "
";
    }

    protected function addConstants(&$script)
    {
        $table = $this->getTable();
        $tableName = $table->getName();

        $colname = array();

        foreach ($table->getColumns() as $col) {
            if ($col->isNestedSetLeftKey()) {
                $colname['left'] = $tableName . '.' . $col->getName();
            }

            if ($col->isNestedSetRightKey()) {
                $colname['right'] = $tableName . '.' . $col->getName();
            }

            if ($col->isTreeScopeKey()) {
                $colname['scope'] = $tableName . '.' . $col->getName();
            }

            if (3 == count($colname)) {
                break;
            }
        }

        if (!isset($colname['left'])) {
            throw new EngineException("One column must have nestedSetLeftKey attribute set to true for [" . $table->getName() . "] table");
        }

        if (!isset($colname['right'])) {
            throw new EngineException("One column must have nestedSetRightKey attribute set to true for [" . $table->getName() . "] table");
        }

        $colname['scope'] = isset($colname['scope']) ? $colname['scope'] : null;

        $script .= "
    /**
     * Left column for the set
     */
    const LEFT_COL = " . var_export($colname['left'], true) . ";

    /**
     * Right column for the set
     */
    const RIGHT_COL = " . var_export($colname['right'], true) . ";

    /**
     * Scope column for the set
     */
    const SCOPE_COL = " . var_export($colname['scope'], true) . ";
";
    }

    protected function addCreateRoot(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Creates the supplied node as the root node.
     *
     * @param                  $objectClassname \$node	Propel object for model
     * @throws PropelException
     */
    public static function createRoot(NodeObject \$node)
    {
        if (\$node->getLeftValue()) {
            throw new PropelException('Cannot turn an existing node into a root node.');
        }

        \$node->setLeftValue(1);
        \$node->setRightValue(2);
    }
";
    }

    protected function addRetrieveRoot(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Returns the root node for a given scope id
     *
     * @param      int \$scopeId		Scope id to determine which root node to return
     * @param      PropelPDO \$con	Connection to use.
     * @return   $objectClassname			Propel object for root node
     */
    public static function retrieveRoot(\$scopeId = null, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);

        \$c->add(self::LEFT_COL, 1, Criteria::EQUAL);

        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$scopeId, Criteria::EQUAL);
        }

        return $peerClassname::doSelectOne(\$c, \$con);
    }
";
    }

    protected function addInsertAsFirstChildOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$child as first child of given \$parent node
     *
     * @param   $objectClassname \$child	Propel object for child node
     * @param   $objectClassname \$parent	Propel object for parent node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertAsFirstChildOf(NodeObject \$child, NodeObject \$parent, PropelPDO \$con = null)
    {
        // Update \$child node properties
        \$child->setLeftValue(\$parent->getLeftValue() + 1);
        \$child->setRightValue(\$parent->getLeftValue() + 2);
        \$child->setParentNode(\$parent);

        \$sidv = null;
        if (self::SCOPE_COL) {
            \$child->setScopeIdValue(\$sidv = \$parent->getScopeIdValue());
        }

        // Update database nodes
        self::shiftRLValues(\$child->getLeftValue(), 2, \$con, \$sidv);

        // Update all loaded nodes
        self::updateLoadedNode(\$parent, 2, \$con);
    }
";
    }

    protected function addInsertAsLastChildOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$child as last child of destination node \$parent
     *
     * @param   $objectClassname \$child		Propel object for child node
     * @param   $objectClassname \$parent	Propel object for parent node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertAsLastChildOf(NodeObject \$child, NodeObject \$parent, PropelPDO \$con = null)
    {
        // Update \$child node properties
        \$child->setLeftValue(\$parent->getRightValue());
        \$child->setRightValue(\$parent->getRightValue() + 1);
        \$child->setParentNode(\$parent);

        \$sidv = null;
        if (self::SCOPE_COL) {
            \$child->setScopeIdValue(\$sidv = \$parent->getScopeIdValue());
        }

        // Update database nodes
        self::shiftRLValues(\$child->getLeftValue(), 2, \$con, \$sidv);

        // Update all loaded nodes
        self::updateLoadedNode(\$parent, 2, \$con);
    }
";
    }

    protected function addInsertAsPrevSiblingOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$sibling as previous sibling to destination node \$node
     *
     * @param   $objectClassname \$node		Propel object for destination node
     * @param   $objectClassname \$sibling	Propel object for source node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertAsPrevSiblingOf(NodeObject \$node, NodeObject \$sibling, PropelPDO \$con = null)
    {
        if (\$sibling->isRoot()) {
            throw new PropelException('Root nodes cannot have siblings');
        }

        \$node->setLeftValue(\$sibling->getLeftValue());
        \$node->setRightValue(\$sibling->getLeftValue() + 1);
        \$node->setParentNode(\$sibling->retrieveParent());

        \$sidv = null;
        if (self::SCOPE_COL) {
            \$node->setScopeIdValue(\$sidv = \$sibling->getScopeIdValue());
        }

        // Update database nodes
        self::shiftRLValues(\$node->getLeftValue(), 2, \$con, \$sidv);

        // Update all loaded nodes
        self::updateLoadedNode(\$sibling->retrieveParent(), 2, \$con);
    }
";
    }

    protected function addInsertAsNextSiblingOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$sibling as next sibling to destination node \$node
     *
     * @param   $objectClassname \$node		Propel object for destination node
     * @param   $objectClassname \$sibling	Propel object for source node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertAsNextSiblingOf(NodeObject \$node, NodeObject \$sibling, PropelPDO \$con = null)
    {
        if (\$sibling->isRoot()) {
            throw new PropelException('Root nodes cannot have siblings');
        }

        \$node->setLeftValue(\$sibling->getRightValue() + 1);
        \$node->setRightValue(\$sibling->getRightValue() + 2);
        \$node->setParentNode(\$sibling->retrieveParent());

        \$sidv = null;
        if (self::SCOPE_COL) {
            \$node->setScopeIdValue(\$sidv = \$sibling->getScopeIdValue());
        }

        // Update database nodes
        self::shiftRLValues(\$node->getLeftValue(), 2, \$con, \$sidv);

        // Update all loaded nodes
        self::updateLoadedNode(\$sibling->retrieveParent(), 2, \$con);
    }
";
    }

    protected function addInsertAsParentOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$parent as parent of given node.
     *
     * @param   $objectClassname \$parent	Propel object for given parent node
     * @param   $objectClassname \$node	Propel object for given destination node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertAsParentOf(NodeObject \$parent, NodeObject \$node, PropelPDO \$con = null)
    {
        \$sidv = null;
        if (self::SCOPE_COL) {
            \$sidv = \$node->getScopeIdValue();
        }

        self::shiftRLValues(\$node->getLeftValue(), 1, \$con, \$sidv);
        self::shiftRLValues(\$node->getRightValue() + 2, 1, \$con, \$sidv);

        if (self::SCOPE_COL) {
            \$parent->setScopeIdValue(\$sidv);
        }

        \$parent->setLeftValue(\$node->getLeftValue());
        \$parent->setRightValue(\$node->getRightValue() + 2);

        \$previous_parent = \$node->retrieveParent();
        \$parent->setParentNode(\$previous_parent);
        \$node->setParentNode(\$parent);

        \$node->save(\$con);

        // Update all loaded nodes
        self::updateLoadedNode(\$previous_parent, 2, \$con);
    }
";
    }

    protected function addInsertRoot(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$node as root node
     *
     * @param   $objectClassname \$node	Propel object as root node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertRoot(NodeObject \$node, PropelPDO \$con = null)
    {
        \$sidv = null;
        if (self::SCOPE_COL) {
            \$sidv = \$node->getScopeIdValue();
        }

        $peerClassname::insertAsParentOf($peerClassname::retrieveRoot(\$sidv, \$con), \$node, \$con);
    }
";
    }

    protected function addInsertParent(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Inserts \$parent as parent to destination node \$child
     *
     * @deprecated 1.3 - 2007/11/06
     * @see        insertAsParentOf()
     * @param   $objectClassname \$child	Propel object to become child node
     * @param   $objectClassname \$parent	Propel object as parent node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function insertParent(NodeObject \$child, NodeObject \$parent, PropelPDO \$con = null)
    {
        self::insertAsParentOf(\$parent, \$child, \$con);
    }
";
    }

    protected function addDeleteRoot(&$script)
    {
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Delete root node
     *
     * @param      PropelPDO \$con	Connection to use.
     * @return boolean Deletion status
     */
    public static function deleteRoot(\$scopeId = null, PropelPDO \$con = null)
    {
        if (!self::SCOPE_COL) {
            \$scopeId = null;
        }
        \$root = $peerClassname::retrieveRoot(\$scopeId, \$con);
        if ($peerClassname::getNumberOfChildren(\$root) == 1) {
            return $peerClassname::deleteNode(\$root, \$con);
        } else {
            return false;
        }
    }
";
    }

    protected function addDeleteNode(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Delete \$dest node
     *
     * @param   $objectClassname \$dest	Propel object node to delete
     * @param      PropelPDO \$con	Connection to use.
     * @return boolean Deletion status
     */
    public static function deleteNode(NodeObject \$dest, PropelPDO \$con = null)
    {
        if (\$dest->getLeftValue() == 1) {
            // deleting root implies conditions (see deleteRoot() method)
            return $peerClassname::deleteRoot(\$con);
        }

        \$sidv = null;
        if (self::SCOPE_COL) {
            \$sidv = \$dest->getScopeIdValue();
        }

        self::shiftRLRange(\$dest->getLeftValue(), \$dest->getRightValue(), -1, \$con, \$sidv);
        self::shiftRLValues(\$dest->getRightValue() + 1, -2, \$con, \$sidv);

        return \$dest->delete(\$con);
    }
";
    }

    protected function addMoveToFirstChildOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Moves \$child to be first child of \$parent
     *
     * @param   $objectClassname \$parent	Propel object for parent node
     * @param   $objectClassname \$child		Propel object for child node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function moveToFirstChildOf(NodeObject \$parent, NodeObject \$child, PropelPDO \$con = null)
    {
        if (\$parent->getScopeIdValue() != \$child->getScopeIdValue()) {
            throw new PropelException('Moving nodes across trees is not supported');
        }
        \$destLeft = \$parent->getLeftValue() + 1;
        self::updateDBNode(\$child, \$destLeft, \$con);

        // Update all loaded nodes
        self::updateLoadedNode(\$parent, 2, \$con);
    }
";
    }

    protected function addMoveToLastChildOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Moves \$child to be last child of \$parent
     *
     * @param   $objectClassname \$parent	Propel object for parent node
     * @param   $objectClassname \$child		Propel object for child node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function moveToLastChildOf(NodeObject \$parent, NodeObject \$child, PropelPDO \$con = null)
    {
        if (\$parent->getScopeIdValue() != \$child->getScopeIdValue()) {
            throw new PropelException('Moving nodes across trees is not supported');
        }
        \$destLeft = \$parent->getRightValue();
        self::updateDBNode(\$child, \$destLeft, \$con);

        // Update all loaded nodes
        self::updateLoadedNode(\$parent, 2, \$con);
    }
";
    }

    protected function addMoveToPrevSiblingOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Moves \$node to be prev sibling to \$dest
     *
     * @param   $objectClassname \$dest	Propel object for destination node
     * @param   $objectClassname \$node	Propel object for source node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function moveToPrevSiblingOf(NodeObject \$dest, NodeObject \$node, PropelPDO \$con = null)
    {
        if (\$dest->getScopeIdValue() != \$node->getScopeIdValue()) {
            throw new PropelException('Moving nodes across trees is not supported');
        }
        \$destLeft = \$dest->getLeftValue();
        self::updateDBNode(\$node, \$destLeft, \$con);

        // Update all loaded nodes
        self::updateLoadedNode(\$dest->retrieveParent(), 2, \$con);
    }
";
    }

    protected function addMoveToNextSiblingOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Moves \$node to be next sibling to \$dest
     *
     * @param   $objectClassname \$dest	Propel object for destination node
     * @param   $objectClassname \$node	Propel object for source node
     * @param      PropelPDO \$con	Connection to use.
     * @return void
     */
    public static function moveToNextSiblingOf(NodeObject \$dest, NodeObject \$node, PropelPDO \$con = null)
    {
        if (\$dest->getScopeIdValue() != \$node->getScopeIdValue()) {
            throw new PropelException('Moving nodes across trees is not supported');
        }
        \$destLeft = \$dest->getRightValue();
        \$destLeft = \$destLeft + 1;
        self::updateDBNode(\$node, \$destLeft, \$con);

        // Update all loaded nodes
        self::updateLoadedNode(\$dest->retrieveParent(), 2, \$con);
    }
";
    }

    protected function addRetrieveFirstChild(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets first child for the given node if it exists
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return mixed Propel object if exists else false
     */
    public static function retrieveFirstChild(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->add(self::LEFT_COL, \$node->getLeftValue() + 1, Criteria::EQUAL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }

        return $peerClassname::doSelectOne(\$c, \$con);
    }
";
    }

    protected function addRetrieveLastChild(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets last child for the given node if it exists
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return mixed Propel object if exists else false
     */
    public static function retrieveLastChild(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->add(self::RIGHT_COL, \$node->getRightValue() - 1, Criteria::EQUAL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }

        return $peerClassname::doSelectOne(\$c, \$con);
    }
";
    }

    protected function addRetrievePrevSibling(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets prev sibling for the given node if it exists
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return mixed Propel object if exists else null
     */
    public static function retrievePrevSibling(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->add(self::RIGHT_COL, \$node->getLeftValue() - 1, Criteria::EQUAL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$prevSibling = $peerClassname::doSelectOne(\$c, \$con);
        \$node->setPrevSibling(\$prevSibling);

        return \$prevSibling;
    }
";
    }

    protected function addRetrieveNextSibling(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets next sibling for the given node if it exists
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return mixed Propel object if exists else false
     */
    public static function retrieveNextSibling(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->add(self::LEFT_COL, \$node->getRightValue() + 1, Criteria::EQUAL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$nextSibling = $peerClassname::doSelectOne(\$c, \$con);
        \$node->setNextSibling(\$nextSibling);

        return \$nextSibling;
    }
";
    }

    protected function addRetrieveTree(&$script)
    {
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Retrieves the entire tree from root
     *
     * @param      PropelPDO \$con	Connection to use.
     */
    public static function retrieveTree(\$scopeId = null, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->addAscendingOrderByColumn(self::LEFT_COL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$scopeId, Criteria::EQUAL);
        }
        \$stmt = $peerClassname::doSelectStmt(\$c, \$con);
        if (false !== (\$row = \$stmt->fetch(PDO::FETCH_NUM))) {
            \$omClass = $peerClassname::getOMClass(\$row, 0);
            \$cls = substr('.'.\$omClass, strrpos('.'.\$omClass, '.') + 1);

            \$key = " . $peerClassname . "::getPrimaryKeyHashFromRow(\$row, 0);
            if (null === (\$root = " . $peerClassname . "::getInstanceFromPool(\$key))) {
                " . $this->buildObjectInstanceCreationCode('$root', '$cls') . "
                \$root->hydrate(\$row);
            }

            \$root->setLevel(0);
            $peerClassname::hydrateDescendants(\$root, \$stmt);
            $peerClassname::addInstanceToPool(\$root);

            \$stmt->closeCursor();

            return \$root;
        }

        return false;
    }
";
    }

    protected function addRetrieveBranch(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Retrieves the entire tree from parent \$node
     *
     * @param   $objectClassname \$node	Propel object for parent node
     * @param      PropelPDO \$con	Connection to use.
     */
    public static function retrieveBranch(NodeObject \$node, PropelPDO \$con = null)
    {
        return $peerClassname::retrieveDescendants(\$node, \$con);
    }
";
    }

    protected function addRetrieveChildren(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets direct children for the node
     *
     * @param   $objectClassname \$node	Propel object for parent node
     * @param      PropelPDO \$con	Connection to use.
     */
    public static function retrieveChildren(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->addAscendingOrderByColumn(self::LEFT_COL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$c->add(self::LEFT_COL, \$node->getLeftValue(), Criteria::GREATER_THAN);
        \$c->addAnd(self::RIGHT_COL, \$node->getRightValue(), Criteria::LESS_THAN);
        \$stmt = $peerClassname::doSelectStmt(\$c, \$con);

        return $peerClassname::hydrateChildren(\$node, \$stmt);
    }
";
    }

    protected function addRetrieveDescendants(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets all descendants for the node
     *
     * @param   $objectClassname \$node	Propel object for parent node
     * @param      PropelPDO \$con	Connection to use.
     */
    public static function retrieveDescendants(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c->addAscendingOrderByColumn(self::LEFT_COL);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$c->add(self::LEFT_COL, \$node->getLeftValue(), Criteria::GREATER_THAN);
        \$c->addAnd(self::RIGHT_COL, \$node->getRightValue(), Criteria::LESS_THAN);
        \$stmt = $peerClassname::doSelectStmt(\$c, \$con);

        return $peerClassname::hydrateDescendants(\$node, \$stmt);
    }
";
    }

    protected function addRetrieveSiblings(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets all siblings for the node
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     */
    public static function retrieveSiblings(NodeObject \$node, PropelPDO \$con = null)
    {
        \$parent = $peerClassname::retrieveParent(\$node, \$con);
        \$siblings = $peerClassname::retrieveChildren(\$parent, \$con);

        return \$siblings;
    }
";
    }

    protected function addRetrieveParent(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets immediate ancestor for the given node if it exists
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return mixed Propel object if exists else null
     */
    public static function retrieveParent(NodeObject \$node, PropelPDO \$con = null)
    {
        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c1 = \$c->getNewCriterion(self::LEFT_COL, \$node->getLeftValue(), Criteria::LESS_THAN);
        \$c2 = \$c->getNewCriterion(self::RIGHT_COL, \$node->getRightValue(), Criteria::GREATER_THAN);

        \$c1->addAnd(\$c2);

        \$c->add(\$c1);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$c->addAscendingOrderByColumn(self::RIGHT_COL);

        \$parent = $peerClassname::doSelectOne(\$c, \$con);

        \$node->setParentNode(\$parent);

        return \$parent;
    }
";
    }

    protected function addGetLevel(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets level for the given node
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return int Level for the given node
     */
    public static function getLevel(NodeObject \$node, PropelPDO \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_READ);
        }

        \$sql = \"SELECT COUNT(*) AS lvl FROM \" . self::TABLE_NAME . \" WHERE \" . self::LEFT_COL . \" < :left AND \" . self::RIGHT_COL . \" > :right\";

        if (self::SCOPE_COL) {
            \$sql .= ' AND ' . self::SCOPE_COL . ' = :scope';
        }

        \$stmt = \$con->prepare(\$sql);
        \$stmt->bindValue(':left', \$node->getLeftValue(), PDO::PARAM_INT);
        \$stmt->bindValue(':right', \$node->getRightValue(), PDO::PARAM_INT);
        if (self::SCOPE_COL) {
            \$stmt->bindValue(':scope', \$node->getScopeIdValue());
        }
        \$stmt->execute();
        \$row = \$stmt->fetch();

        return \$row['lvl'];
    }
";
    }

    protected function addGetNumberOfChildren(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets number of direct children for given node
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return int Level for the given node
     */
    public static function getNumberOfChildren(NodeObject \$node, PropelPDO \$con = null)
    {
        \$children = $peerClassname::retrieveChildren(\$node);

        return count(\$children);
    }
";
    }

    protected function addGetNumberOfDescendants(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Gets number of descendants for given node
     *
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PropelPDO \$con	Connection to use.
     * @return int Level for the given node
     */
    public static function getNumberOfDescendants(NodeObject \$node, PropelPDO \$con = null)
    {
        \$right = \$node->getRightValue();
        \$left = \$node->getLeftValue();
        \$num = (\$right - \$left - 1) / 2;

        return \$num;
    }
";
    }

    protected function addGetPath(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Returns path to a specific node as an array, useful to create breadcrumbs
     *
     * @param   $objectClassname \$node	Propel object of node to create path to
     * @param      PropelPDO \$con	Connection to use.
     * @return array Array in order of hierarchy
     */
    public static function getPath(NodeObject \$node, PropelPDO \$con = null)
    {
        \$criteria = new Criteria();
        if (self::SCOPE_COL) {
            \$criteria->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$criteria->add(self::LEFT_COL, \$node->getLeftValue(), Criteria::LESS_EQUAL);
        \$criteria->add(self::RIGHT_COL, \$node->getRightValue(), Criteria::GREATER_EQUAL);
        \$criteria->addAscendingOrderByColumn(self::LEFT_COL);

        return self::doSelect(\$criteria, \$con);
    }
";
    }

    protected function addIsValid(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if node is valid
     *
     * @param       $objectClassname \$node	Propel object for src node
     * @return bool
     */
    public static function isValid(NodeObject \$node = null)
    {
        if (is_object(\$node) && \$node->getRightValue() > \$node->getLeftValue()) {
            return true;
        } else {
            return false;
        }
    }
";
    }

    protected function addIsRoot(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if node is a root
     *
     * @param       $objectClassname \$node	Propel object for src node
     * @return bool
     */
    public static function isRoot(NodeObject \$node)
    {
        return (\$node->getLeftValue()==1);
    }
";
    }

    protected function addIsLeaf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if node is a leaf
     *
     * @param       $objectClassname \$node	Propel object for src node
     * @return bool
     */
    public static function isLeaf(NodeObject \$node)
    {
        return ((\$node->getRightValue()-\$node->getLeftValue())==1);
    }
";
    }

    protected function addIsChildOf(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$child is a child of \$parent
     *
     * @param       $objectClassname \$child	Propel object for node
     * @param       $objectClassname \$parent	Propel object for node
     * @return bool
     */
    public static function isChildOf(NodeObject \$child, NodeObject \$parent)
    {
        return ((\$child->getLeftValue()>\$parent->getLeftValue()) && (\$child->getRightValue()<\$parent->getRightValue()));
    }
";
    }

    protected function addIsChildOfOrSiblingTo(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node1 is a child of or equal to \$node2
     *
     * @deprecated 1.3 - 2007/11/09
     * @param       $objectClassname \$node1		Propel object for node
     * @param       $objectClassname \$node2		Propel object for node
     * @return bool
     */
    public static function isChildOfOrSiblingTo(NodeObject \$node1, NodeObject \$node2)
    {
        return ((\$node1->getLeftValue()>=\$node2->getLeftValue()) and (\$node1->getRightValue()<=\$node2->getRightValue()));
    }
";
    }

    protected function addIsEqualTo(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node1 is equal to \$node2
     *
     * @param       $objectClassname \$node1		Propel object for node
     * @param       $objectClassname \$node2		Propel object for node
     * @return bool
     */
    public static function isEqualTo(NodeObject \$node1, NodeObject \$node2)
    {
        \$also = true;
        if (self::SCOPE_COL) {
            \$also = (\$node1->getScopeIdValue() === \$node2->getScopeIdValue());
        }

        return \$node1->getLeftValue() == \$node2->getLeftValue() && \$node1->getRightValue() == \$node2->getRightValue() && \$also;
    }
";
    }

    protected function addHasParent(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node has an ancestor
     *
     * @param   $objectClassname \$node		Propel object for node
     * @param      PropelPDO \$con		Connection to use.
     * @return bool
     */
    public static function hasParent(NodeObject \$node, PropelPDO \$con = null)
    {
        return $peerClassname::isValid($peerClassname::retrieveParent(\$node, \$con));
    }
";
    }

    protected function addHasPrevSibling(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node has prev sibling
     *
     * @param   $objectClassname \$node		Propel object for node
     * @param      PropelPDO \$con		Connection to use.
     * @return bool
     */
    public static function hasPrevSibling(NodeObject \$node, PropelPDO \$con = null)
    {
        return $peerClassname::isValid($peerClassname::retrievePrevSibling(\$node, \$con));
    }
";
    }

    protected function addHasNextSibling(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node has next sibling
     *
     * @param   $objectClassname \$node		Propel object for node
     * @param      PropelPDO \$con		Connection to use.
     * @return bool
     */
    public static function hasNextSibling(NodeObject \$node, PropelPDO \$con = null)
    {
        return $peerClassname::isValid($peerClassname::retrieveNextSibling(\$node, \$con));
    }
";
    }

    protected function addHasChildren(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Tests if \$node has children
     *
     * @param       $objectClassname \$node		Propel object for node
     * @return bool
     */
    public static function hasChildren(NodeObject \$node)
    {
        return ((\$node->getRightValue()-\$node->getLeftValue())>1);
    }
";
    }

    protected function addDeleteDescendants(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Deletes \$node and all of its descendants
     *
     * @param   $objectClassname \$node		Propel object for source node
     * @param      PropelPDO \$con		Connection to use.
     */
    public static function deleteDescendants(NodeObject \$node, PropelPDO \$con = null)
    {
        \$left = \$node->getLeftValue();
        \$right = \$node->getRightValue();

        \$c = new Criteria($peerClassname::DATABASE_NAME);
        \$c1 = \$c->getNewCriterion(self::LEFT_COL, \$left, Criteria::GREATER_THAN);
        \$c2 = \$c->getNewCriterion(self::RIGHT_COL, \$right, Criteria::LESS_THAN);

        \$c1->addAnd(\$c2);

        \$c->add(\$c1);
        if (self::SCOPE_COL) {
            \$c->add(self::SCOPE_COL, \$node->getScopeIdValue(), Criteria::EQUAL);
        }
        \$c->addAscendingOrderByColumn(self::RIGHT_COL);

        \$result = $peerClassname::doDelete(\$c, \$con);

        self::shiftRLValues(\$right + 1, \$left - \$right -1, \$con, \$node->getScopeIdValue());

        return \$result;
    }
";
    }

    protected function addGetNode(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Returns a node given its primary key or the node itself
     *
     * @param      int/$objectClassname \$node	Primary key/instance of required node
     * @param      PropelPDO \$con		Connection to use.
     * @return object Propel object for model
     */
    public static function getNode(\$node, PropelPDO \$con = null)
    {
        if (is_object(\$node)) {
            return \$node;
        } else {
            \$object = $peerClassname::retrieveByPK(\$node, \$con);
            \$rtn = is_object(\$object) ? \$object : false;

            return \$rtn;
        }
    }
";
    }

    protected function addHydrateDescendants(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $table = $this->getTable();
        $script .= "
    /**
     * Hydrate recursively the descendants of the given node
     * @param   $objectClassname \$node	Propel object for src node
     * @param      PDOStatement \$stmt	Executed PDOStatement
     */
    protected static function hydrateDescendants(NodeObject \$node, PDOStatement \$stmt)
    {
        \$descendants = array();
        \$children = array();
        \$prevSibling = null;
";

        if (!$table->getChildrenColumn()) {
            $script .= "
        // set the class once to avoid overhead in the loop
        \$cls = $peerClassname::getOMClass();
        \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
        }

        $script .= "
        while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
            \$key = " . $peerClassname . "::getPrimaryKeyHashFromRow(\$row, 0);
            if (null === (\$child = " . $peerClassname . "::getInstanceFromPool(\$key))) {";

        if ($table->getChildrenColumn()) {
            $script .= "
                // class must be set each time from the record row
                \$cls = " . $peerClassname . "::getOMClass(\$row, 0);
                \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
        }

        $script .= "
                " . $this->buildObjectInstanceCreationCode('$child', '$cls') . "
                \$child->hydrate(\$row);
            }

            \$child->setLevel(\$node->getLevel() + 1);
            \$child->setParentNode(\$node);
            if (!empty(\$prevSibling)) {
                \$child->setPrevSibling(\$prevSibling);
                \$prevSibling->setNextSibling(\$child);
            }

            \$descendants[] = \$child;

            if (\$child->hasChildren()) {
                \$descendants = array_merge(\$descendants, $peerClassname::hydrateDescendants(\$child, \$stmt));
            } else {
                \$child->setChildren(array());
            }

            \$children[] = \$child;
            \$prevSibling = \$child;

            $peerClassname::addInstanceToPool(\$child);
            if (\$child->getRightValue() + 1 == \$node->getRightValue()) {
                \$child->setNextSibling(null);
                break;
            }
        }
        \$node->setChildren(\$children);

        return \$descendants;
    }
";
    }

    protected function addHydrateChildren(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $table = $this->getTable();
        $script .= "
    /**
     * Hydrate the children of the given node
     * @param   $objectClassname \$node Propel object for src node
     * @param      PDOStatement \$stmt Executed PDOStatement
     */
    protected static function hydrateChildren(NodeObject \$node, PDOStatement \$stmt)
    {
        \$children = array();
        \$prevRight = 0;
";

        if (!$table->getChildrenColumn()) {
            $script .= "
        // set the class once to avoid overhead in the loop
        \$cls = $peerClassname::getOMClass();
        \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
        }

        $script .= "
        while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
            \$key = " . $peerClassname . "::getPrimaryKeyHashFromRow(\$row, 0);
            if (null === (\$child = " . $peerClassname . "::getInstanceFromPool(\$key))) {";

        if ($table->getChildrenColumn()) {
            $script .= "
                // class must be set each time from the record row
                \$cls = " . $peerClassname . "::getOMClass(\$row, 0);
                \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
        }

        $script .= "
                " . $this->buildObjectInstanceCreationCode('$child', '$cls') . "
                \$child->hydrate(\$row);
            }

            \$child->setLevel(\$node->getLevel() + 1);

            if (\$child->getRightValue() > \$prevRight) {
                \$children[] = \$child;
                \$prevRight = \$child->getRightValue();
            }

            if (\$child->getRightValue() + 1 == \$node->getRightValue()) {
                break;
            }
        }
        \$node->setChildren(\$children);

        return \$children;
    }
";
    }

    /**
     * @deprecated 1.3 - 2008/03/11
     * Won't be fixed, defect by design
     * Never trust it
     */
    protected function addShiftRParent(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Adds '\$delta' to all parent R values.
     * '\$delta' can also be negative.
     *
     * @deprecated 1.3 - 2008/03/11
     * @param   $objectClassname \$node	Propel object for parent node
     * @param      int \$delta	Value to be shifted by, can be negative
     * @param      PropelPDO \$con		Connection to use.
     */
    protected static function shiftRParent(NodeObject \$node, \$delta, PropelPDO \$con = null)
    {
        if (\$node->hasParent(\$con)) {
            \$parent = \$node->retrieveParent();
            self::shiftRParent(\$parent, \$delta, \$con);
        }
        \$node->setRightValue(\$node->getRightValue() + \$delta);
    }
";
    }

    protected function addUpdateLoadedNode(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $table = $this->getTable();

        $script .= "
    /**
     * Reload all already loaded nodes to sync them with updated db
     *
     * @param   $objectClassname \$node	Propel object for parent node
     * @param      int \$delta	Value to be shifted by, can be negative
     * @param      PropelPDO \$con		Connection to use.
     */
    protected static function updateLoadedNode(NodeObject \$node, \$delta, PropelPDO \$con = null)
    {
        if (Propel::isInstancePoolingEnabled()) {
            \$keys = array();
            foreach (self::\$instances as \$obj) {
                \$keys[] = \$obj->getPrimaryKey();
            }

            if (!empty(\$keys)) {
                // We don't need to alter the object instance pool; we're just modifying these ones
                // already in the pool.
                \$criteria = new Criteria(self::DATABASE_NAME);";
        if (count($table->getPrimaryKey()) === 1) {
            $pkey = $table->getPrimaryKey();
            $col = array_shift($pkey);
            $script .= "
                \$criteria->add(" . $this->getColumnConstant($col) . ", \$keys, Criteria::IN);
";
        } else {
            $fields = array();
            foreach ($table->getPrimaryKey() as $k => $col) {
                $fields[] = $this->getColumnConstant($col);
            };
            $script .= "

                // Loop on each instances in pool
                foreach (\$keys as \$values) {
                  // Create initial Criterion
                    \$cton = \$criteria->getNewCriterion(" . $fields[0] . ", \$values[0]);";
            unset($fields[0]);
            foreach ($fields as $k => $col) {
                $script .= "

                    // Create next criterion
                    \$nextcton = \$criteria->getNewCriterion(" . $col . ", \$values[$k]);
                    // And merge it with the first
                    \$cton->addAnd(\$nextcton);";
            }
            $script .= "

                    // Add final Criterion to Criteria
                    \$criteria->addOr(\$cton);
                }";
        }

        $script .= "
                \$stmt = $peerClassname::doSelectStmt(\$criteria, \$con);
                while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
                    \$key = $peerClassname::getPrimaryKeyHashFromRow(\$row, 0);
                    if (null !== (\$object = $peerClassname::getInstanceFromPool(\$key))) {";
        $n = 0;
        foreach ($table->getColumns() as $col) {
            if ($col->isNestedSetLeftKey()) {
                $script .= "
                        \$object->setLeftValue(\$row[$n]);";
            } elseif ($col->isNestedSetRightKey()) {
                $script .= "
                        \$object->setRightValue(\$row[$n]);";
            }
            $n++;
        }
        $script .= "
                    }
                }
                \$stmt->closeCursor();
            }
        }
    }
";
    }

    protected function addUpdateDBNode(&$script)
    {
        $objectClassname = $this->getStubObjectBuilder()->getClassname();
        $script .= "
    /**
     * Move \$node and its children to location \$destLeft and updates rest of tree
     *
     * @param   $objectClassname \$node Propel object for node to update
     * @param      int	\$destLeft Destination left value
     * @param      PropelPDO \$con		Connection to use.
     */
    protected static function updateDBNode(NodeObject \$node, \$destLeft, PropelPDO \$con = null)
    {
        \$left = \$node->getLeftValue();
        \$right = \$node->getRightValue();

        \$treeSize = \$right - \$left +1;

        self::shiftRLValues(\$destLeft, \$treeSize, \$con, \$node->getScopeIdValue());

        if (\$left >= \$destLeft) { // src was shifted too?
            \$left += \$treeSize;
            \$right += \$treeSize;
        }

        // now there's enough room next to target to move the subtree
        self::shiftRLRange(\$left, \$right, \$destLeft - \$left, \$con, \$node->getScopeIdValue());

        // correct values after source
        self::shiftRLValues(\$right + 1, -\$treeSize, \$con, \$node->getScopeIdValue());
    }
";
    }

    protected function addShiftRLValues(&$script)
    {
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Adds '\$delta' to all L and R values that are >= '\$first'. '\$delta' can also be negative.
     *
     * @param      int \$first		First node to be shifted
     * @param      int \$delta		Value to be shifted by, can be negative
     * @param      PropelPDO \$con		Connection to use.
     */
    protected static function shiftRLValues(\$first, \$delta, PropelPDO \$con = null, \$scopeId = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
        }

        \$leftUpdateCol = self::LEFT_COL;
        \$rightUpdateCol = self::RIGHT_COL;

        // Shift left column values
        \$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$criterion = \$whereCriteria->getNewCriterion(
            self::LEFT_COL,
            \$first,
            Criteria::GREATER_EQUAL);

        if (self::SCOPE_COL) {
            \$criterion->addAnd(
                \$whereCriteria->getNewCriterion(
                    self::SCOPE_COL,
                    \$scopeId,
                    Criteria::EQUAL));
        }
        \$whereCriteria->add(\$criterion);

        \$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$valuesCriteria->add(
            self::LEFT_COL,
            array('raw' => \$leftUpdateCol . ' + ?', 'value' => \$delta),
            Criteria::CUSTOM_EQUAL);

        {$this->basePeerClassname}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);

        // Shift right column values
        \$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$criterion = \$whereCriteria->getNewCriterion(
            self::RIGHT_COL,
            \$first,
            Criteria::GREATER_EQUAL);

        if (self::SCOPE_COL) {
            \$criterion->addAnd(
                \$whereCriteria->getNewCriterion(
                    self::SCOPE_COL,
                    \$scopeId,
                    Criteria::EQUAL));
        }
        \$whereCriteria->add(\$criterion);

        \$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$valuesCriteria->add(
          self::RIGHT_COL,
            array('raw' => \$rightUpdateCol . ' + ?', 'value' => \$delta),
            Criteria::CUSTOM_EQUAL);

        {$this->basePeerClassname}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
    }
";
    }

    protected function addShiftRLRange(&$script)
    {
        $peerClassname = $this->getStubPeerBuilder()->getClassname();
        $script .= "
    /**
     * Adds '\$delta' to all L and R values that are >= '\$first' and <= '\$last'.
     * '\$delta' can also be negative.
     *
     * @param      int \$first	First node to be shifted (L value)
     * @param      int \$last	Last node to be shifted (L value)
     * @param      int \$delta	Value to be shifted by, can be negative
     * @param      PropelPDO \$con		Connection to use.
     * @return array Shifted L and R values
     */
    protected static function shiftRLRange(\$first, \$last, \$delta, PropelPDO \$con = null, \$scopeId = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
        }

        \$leftUpdateCol = substr(self::LEFT_COL, strrpos(self::LEFT_COL, '.') + 1);
        \$rightUpdateCol = substr(self::RIGHT_COL, strrpos(self::RIGHT_COL, '.') + 1);

        // Shift left column values
        \$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$criterion = \$whereCriteria->getNewCriterion(self::LEFT_COL, \$first, Criteria::GREATER_EQUAL);
        \$criterion->addAnd(\$whereCriteria->getNewCriterion(self::LEFT_COL, \$last, Criteria::LESS_EQUAL));
        if (self::SCOPE_COL) {
            \$criterion->addAnd(\$whereCriteria->getNewCriterion(self::SCOPE_COL, \$scopeId, Criteria::EQUAL));
        }
        \$whereCriteria->add(\$criterion);

        \$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$valuesCriteria->add(
            self::LEFT_COL,
            array('raw' => \$leftUpdateCol . ' + ?', 'value' => \$delta),
            Criteria::CUSTOM_EQUAL);

        {$this->basePeerClassname}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);

        // Shift right column values
        \$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$criterion = \$whereCriteria->getNewCriterion(self::RIGHT_COL, \$first, Criteria::GREATER_EQUAL);
        \$criterion->addAnd(\$whereCriteria->getNewCriterion(self::RIGHT_COL, \$last, Criteria::LESS_EQUAL));
        if (self::SCOPE_COL) {
            \$criterion->addAnd(\$whereCriteria->getNewCriterion(self::SCOPE_COL, \$scopeId, Criteria::EQUAL));
        }
        \$whereCriteria->add(\$criterion);

        \$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
        \$valuesCriteria->add(
            self::RIGHT_COL,
            array('raw' => \$rightUpdateCol . ' + ?', 'value' => \$delta),
            Criteria::CUSTOM_EQUAL);

        {$this->basePeerClassname}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);

        return array('left' => \$first + \$delta, 'right' => \$last + \$delta);
    }
";
    }
} // PHP5NestedSetPeerBuilder
